iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
0
Modern Web

從技術文章深入學習 JavaScript系列 第 18

Day 18 [123] [前端漫談_1] 從 for of 聊到 Generator

  • 分享至 

  • xImage
  •  

文章選自

作者:dendoink

連接:https://juejin.im/post/6844903762931236878

來源:掘金

for of ?

先來打印看看這個

const testArr = ['foo', 'bar'];

console.log(testArr);

https://ithelp.ithome.com.tw/upload/images/20201002/20124350uB87qZMJUY.png

我們會發現數組( 或是類數組對象比方說Map、arguments、Sets )的__ proto __ 裡面都會有一個Symbol.iterator方法!

打印看看這個方法會出現甚麼

const testArr = ['foo', 'bar'];

// console.log(testArr);

let iterator = testArr[Symbol.iterator]();
// 打印看看這個iterator方法看長怎樣
console.dir(iterator);

https://ithelp.ithome.com.tw/upload/images/20201002/20124350zPbsBcHezX.png

還有一個next方法,來執行看看

const testArr = ['foo', 'bar'];

// console.log(testArr);

let iterator = testArr[Symbol.iterator]();
// 打印看看這個iterator方法看長怎樣
// console.dir(iterator);

// 打印出使用next方法後的回傳值
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

https://ithelp.ithome.com.tw/upload/images/20201002/20124350dxBh8Bu5Rz.png

其實 for of 循環就是基於這個完成遍歷的

  1. 對應下標的值 (回傳的value值)
  2. 遍歷結束的標誌 (回傳的done是否為true)

iterator(迭代器) & The iterator protocol(迭代協議)

先來看一下迭代協議在MDN上面的定義

" The iterable protocol allows JavaScript objects to define or customize their iteration behavior " - MDN

簡單來說就是

JavaScript 允許對象自行定義iteration完成迭代行為

比方說剛剛那個數組的是透過next()方法完成的,這也就是為何對象並不能用for of 進行迭代,因為它本身並沒有定義iterator

let foo = {
  bar: 'bar',
  haha: 'haha'
}
console.dir(foo);

https://ithelp.ithome.com.tw/upload/images/20201002/20124350x1URBX6DhY.png

為Object設置iterator

雖然標準並沒有為我們設置itearator,但我們可以自己設置

Object.prototype[Symbol.iterator] = function*() {
  for (const [key, value] of Object.entries(this)) {
    yield { key, value };
  }
};

for (const { key, value } of { a: 1, b: 2, c: 3 }) {
  console.log(key, value);
}

這個奇怪的格式,就是等等要講的generator

funciotn* () {...}

Generator

直接看例子

// 下面就是generator 函數
function* foo() {
  yield 1
  yield 2 
  yield 3
}

console.dir(foo);

https://ithelp.ithome.com.tw/upload/images/20201002/20124350TzfsMnkMZT.png

居然有我們熟悉的next方法,來實際操作一下foo函數看會發生甚麼

function* foo() {
  yield 1
  yield 2 
  yield 3
}
// console.dir(foo);
let instance = foo()

console.log(instance.next());
console.log(instance.next());
console.log(instance.next());
console.log(instance.next());

https://ithelp.ithome.com.tw/upload/images/20201002/20124350DzGQpwlRM0.png

哇看到這應該滿明顯了吧

當我們generator函數可以創造出iterator,而yield則是中斷代碼執行,可以透過next()方法繼續執行下去

一些generator特性

來看一個奇怪的例子

function* gen() {
  yield 1
  yield* gen2()
  return
  yield 2
}

function* gen2() {
  yield 4
  yield 5
}

let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

https://ithelp.ithome.com.tw/upload/images/20201002/20124350Xj8wtbpsR3.png

  1. 可以發現yield也可以放上generator函數,並會接續執行下去
  2. retrun 後面的yield不會執行

Generator可以幹嘛

終止代碼的特性可以幫我們處理異步

直接看例子

例子

B函數的執行參數是從A傳來,因此需要等A執行完才可以執行B

function* effect() {
  const { param } = yield A();
  const { result } = yield B(param);
  console.table(result);
}
const iterator = effect()
iterator.next()
iterator.next()


上一篇
Day 17 [深拷貝] 如何寫出一個驚艷面試官的深拷貝
下一篇
Day 19 [其他03] 柯里化與反柯里化
系列文
從技術文章深入學習 JavaScript29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言